{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2dc32142",
   "metadata": {},
   "source": [
    "## 基本概念"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee8b86ad",
   "metadata": {},
   "source": [
    "- 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”)。\n",
    "- 可以通过正则表达式，从字符串中获取我们想要的特定部分。\n",
    "- 还可以对目标字符串进行替换操作。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18e431bb",
   "metadata": {},
   "source": [
    "Python语言通过标准库中的re模块支持正则表达式\n",
    "\n",
    "![](images/4.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b743ad18",
   "metadata": {},
   "source": [
    "![](images/5.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "771c7735",
   "metadata": {},
   "source": [
    "**正则表达式修饰符**\n",
    "\n",
    "![](images/6.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87b24537",
   "metadata": {},
   "source": [
    "## match函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f61e14ce",
   "metadata": {},
   "source": [
    "re.match 尝试从字符串的起始位置匹配一个模式，如果不是起始位置匹配成功的话，match()就返回None。\n",
    "\n",
    "语法格式如下：\n",
    "\n",
    "![](images/7.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6dc66068",
   "metadata": {},
   "source": [
    "**意义：**\n",
    "- re.match是用来进行正则匹配检查的方法，如果字符串开头的0个或多个字符匹配正则表达式模式，则返回相应的match对象。\n",
    "\n",
    "- 如果字符串不匹配模式，返回None（注意不是空字符串\"\"）\n",
    "\n",
    "- 匹配对象Match Object具有group()方法， 用来返回字符串的匹配部分\n",
    "\n",
    "- 具有span()方法。返回匹配字符串的位置（元组存储开始，结束位置）\n",
    "\n",
    "- 具有start(),end()方法，存储匹配数据的开始和结束位置。（也可以通过对象的dir(对象查看对象的方法)）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6186f21f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:31:27.955383Z",
     "start_time": "2023-10-13T07:31:27.950343Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 5), match='Hello'>\n",
      "匹配内容： Hello\n",
      "匹配范围： (0, 5)\n",
      "dir函数查看类方法： ['__class__', '__class_getitem__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'end', 'endpos', 'expand', 'group', 'groupdict', 'groups', 'lastgroup', 'lastindex', 'pos', 're', 'regs', 'span', 'start', 'string']\n"
     ]
    }
   ],
   "source": [
    "# 导入模块\n",
    "import re\n",
    "\n",
    "# 定义正则表达式\n",
    "pattern = 'hello'\n",
    "\n",
    "# 目标字符串\n",
    "str = 'Hello world hello'\n",
    "\n",
    "# match函数的使用 -- 大小写敏感\n",
    "result = re.match(pattern, str)\n",
    "print(result)\n",
    "\n",
    "# 忽略大小写\n",
    "result = re.match(pattern, str, re.I)\n",
    "print(result)\n",
    "\n",
    "print('匹配内容：', result.group())\n",
    "print('匹配范围：', result.span())\n",
    "print('dir函数查看类方法：', dir(result))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f64dda86",
   "metadata": {},
   "source": [
    "## 常用匹配符"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcd67843",
   "metadata": {},
   "source": [
    "![](images/8.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e5709e2",
   "metadata": {},
   "source": [
    "一个正则表达式是由字母、数字和特殊字符（括号、星号、问号等）组成。\n",
    "\n",
    "正则表达式中有许多特殊的字符，这些特殊字符是构成正则表达式的要素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "26bfda26",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:35:36.999367Z",
     "start_time": "2023-10-13T07:35:36.994237Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='9'>\n",
      "<re.Match object; span=(0, 1), match='a'>\n",
      "<re.Match object; span=(0, 1), match='B'>\n",
      "<re.Match object; span=(0, 1), match='_'>\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 常用匹配符. 使用 匹配任意一个字符除了(\\n)\n",
    "pattern = '.'\n",
    "\n",
    "str = '9'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'B'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '_'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "# 定义目标式 \\n\n",
    "str = '\\n' \n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "77171de3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:36:26.789344Z",
     "start_time": "2023-10-13T07:36:26.784176Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='0'>\n",
      "<re.Match object; span=(0, 1), match='9'>\n",
      "None\n",
      "None\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "# 常用匹配符 \\d 匹配数字\n",
    "pattern = '\\d'\n",
    "str = '0'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '9'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '_'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'B'\n",
    "print(re.match(pattern, str))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f3ab51fb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:37:09.084831Z",
     "start_time": "2023-10-13T07:37:09.081268Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 1), match='d'>\n"
     ]
    }
   ],
   "source": [
    "# \\D 匹配非数字\n",
    "pattern = '\\D'\n",
    "\n",
    "str = '1'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'd'\n",
    "print(re.match(pattern, str))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "2f92bf0c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:38:35.567941Z",
     "start_time": "2023-10-13T07:38:35.563210Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match=' '>\n",
      "<re.Match object; span=(0, 1), match='\\n'>\n",
      "<re.Match object; span=(0, 1), match='\\t'>\n"
     ]
    }
   ],
   "source": [
    "# \\s 匹配空白字符  即: 空格 \\n \\t\n",
    "pattern = '\\s'\n",
    "str = ' '\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '\\n'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '\\t'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "4d1344e0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:38:58.468151Z",
     "start_time": "2023-10-13T07:38:58.462592Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "None\n",
      "None\n",
      "<re.Match object; span=(0, 1), match='a'>\n",
      "<re.Match object; span=(0, 1), match='_'>\n",
      "<re.Match object; span=(0, 1), match='9'>\n"
     ]
    }
   ],
   "source": [
    "# \\S 匹配 非空白字符串\n",
    "pattern = '\\S'\n",
    "str = ' '\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '\\n'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '\\t'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '_'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '9'\n",
    "print(re.match(pattern,str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "c48fe408",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:40:21.706772Z",
     "start_time": "2023-10-13T07:40:21.699944Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "None\n",
      "None\n",
      "None\n",
      "<re.Match object; span=(0, 1), match='#'>\n",
      "<re.Match object; span=(0, 1), match='@'>\n"
     ]
    }
   ],
   "source": [
    "# \\w 匹配字母 数字 下划线\n",
    "pattern1 = '\\w'\n",
    "\n",
    "# \\W 匹配非 (字母 数字 下划线)\n",
    "pattern2 = '\\W'\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern2, str))\n",
    "\n",
    "str = 'B'\n",
    "print(re.match(pattern2, str))\n",
    "\n",
    "str = '8'\n",
    "print(re.match(pattern2, str))\n",
    "\n",
    "str = '_'\n",
    "print(re.match(pattern2, str))\n",
    "\n",
    "str = '#'\n",
    "print(re.match(pattern2, str))\n",
    "\n",
    "str = '@'\n",
    "print(re.match(pattern2, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3a8be9cd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:40:51.399827Z",
     "start_time": "2023-10-13T07:40:51.394761Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='1'>\n",
      "None\n",
      "<re.Match object; span=(0, 1), match='3'>\n",
      "None\n",
      "None\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "# [] 匹配列表中的字符\n",
    "pattern = '[13579]'\n",
    "str = '1'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '2'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '3'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '4'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern,str))\n",
    "\n",
    "str = '_'\n",
    "print(re.match(pattern,str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "75775bc2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:40:59.550921Z",
     "start_time": "2023-10-13T07:40:59.547666Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 11), match='15456788756'>\n"
     ]
    }
   ],
   "source": [
    "# 匹配手机号码\n",
    "pattern = '1[35789]\\d\\d\\d\\d\\d\\d\\d\\d\\d'\n",
    "str = '15456788756'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58855449",
   "metadata": {},
   "source": [
    "## 限定符"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dfaf8023",
   "metadata": {},
   "source": [
    "从上面示例中可以看到如果要匹配手机号码，需要形如“\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d”这样的正则表达式。\n",
    "\n",
    "其中表现了11次“\\d”，表达方式烦琐。正则表达式作为一门小型的语言，还提供了对表达式的一部分进行重复处理的功能。\n",
    "\n",
    "例如，“*”可以对正则表达式的某个部分重复匹配多次。这种匹配符号称为限定符。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2e69dc1",
   "metadata": {},
   "source": [
    "![](images/9.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "cff1e548",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:44:11.758069Z",
     "start_time": "2023-10-13T07:44:11.754805Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 0), match=''>\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# * 匹配0次或多次\n",
    "pattern = '\\d*'\n",
    "str = 'abc'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "b78fa7c1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:44:22.010293Z",
     "start_time": "2023-10-13T07:44:22.006936Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 4), match='1234'>\n"
     ]
    }
   ],
   "source": [
    "# + 匹配1次或多次\n",
    "pattern = '\\d+'\n",
    "str = '1234abc'\n",
    "\n",
    "print(re.match(pattern,str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "66114dd1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:44:42.527299Z",
     "start_time": "2023-10-13T07:44:42.523587Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 0), match=''>\n"
     ]
    }
   ],
   "source": [
    "# ? 匹配1次或0次\n",
    "pattern = '\\d?'\n",
    "str = 'abc'\n",
    "\n",
    "print(re.match(pattern,str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "27379396",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:44:59.766228Z",
     "start_time": "2023-10-13T07:44:59.762925Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 4), match='1234'>\n"
     ]
    }
   ],
   "source": [
    "# {m} 重复m次\n",
    "pattern = '\\d{4}'\n",
    "str = '12345abc'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "b14e8be5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:45:23.034327Z",
     "start_time": "2023-10-13T07:45:23.031035Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# {m,} 重复至少是m次\n",
    "pattern = '\\d{4,}'\n",
    "str = '123abc'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "8015c2bd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:45:31.916427Z",
     "start_time": "2023-10-13T07:45:31.913194Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# {m,n} 重复匹配 m到n次\n",
    "pattern = '\\d{3,5}'\n",
    "str = '12abc'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5ed8c1f",
   "metadata": {},
   "source": [
    "## 限定符使用案例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ee41b8a8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:47:12.329448Z",
     "start_time": "2023-10-13T07:47:12.325811Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='H'>\n"
     ]
    }
   ],
   "source": [
    "# 导入re模块\n",
    "import re\n",
    "\n",
    "# 匹配出一个字符串首字母为大写字符，后边都是小写字符，这些小写字母可有可无\n",
    "pattern = '[A-Z][a-z]*'\n",
    "\n",
    "str = 'HEabc'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "2523929d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:48:06.847987Z",
     "start_time": "2023-10-13T07:48:06.840824Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='a'>\n",
      "<re.Match object; span=(0, 2), match='ab'>\n",
      "<re.Match object; span=(0, 2), match='a_'>\n",
      "<re.Match object; span=(0, 6), match='_12abA'>\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "# 匹配出有效的变量名\n",
    "\n",
    "pattern = '[a-zA-Z_]\\w*'\n",
    "\n",
    "str = 'a'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'ab'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = 'a_'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '_12abA'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '12abc'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "3e5c5c3e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:49:09.783241Z",
     "start_time": "2023-10-13T07:49:09.779164Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 2), match='10'>\n",
      "<re.Match object; span=(0, 2), match='19'>\n"
     ]
    }
   ],
   "source": [
    "# 匹配出1-99之间的数字\n",
    "pattern = '[1-9]\\d?'\n",
    "\n",
    "str = '10'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '199'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "d7fcded4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:50:06.226529Z",
     "start_time": "2023-10-13T07:50:06.222899Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 9), match='1234_qwer'>\n"
     ]
    }
   ],
   "source": [
    "# 匹配出一个随机密码8-20位以内  (大写字母 小写字母 下划线 数字)\n",
    "pattern = '\\w{8,20}'\n",
    "\n",
    "str = '1234'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "str = '1234_qwer'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cfa9fb93",
   "metadata": {},
   "source": [
    "## 原生字符串"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1d908d1",
   "metadata": {},
   "source": [
    "和大多数编程语言相同，正则表达式里使用 “\\” 作为转义字符，这就可以能造成反斜杠困扰。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "97b1fa53",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:58:58.268319Z",
     "start_time": "2023-10-13T07:58:58.265053Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 4), match='\\\\a\\\\c'>\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 假如你需要匹配文本中的字符 “\\”，那么使用编程语言表示的正则表达式里将需要4个反斜杠 “\\\\”：\n",
    "# 前面两个和后两个分别用于在编程语言里转义成反斜杠，转换成两个反斜杠后再在正则表达式里转义成一个反斜杠\n",
    "pattern = '\\\\\\\\\\w\\\\\\\\\\w'\n",
    "\n",
    "s = '\\\\a\\\\c'\n",
    "\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "22a27f6e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:01:57.062887Z",
     "start_time": "2023-10-13T08:01:57.059470Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 6), match='\\\\\\\\n123'>\n"
     ]
    }
   ],
   "source": [
    "# 使用Python的r前缀\n",
    "# 例如匹配一个数字的“\\d”可以写成 r“\\d”。有了原生字符串，再也不用担心是不是漏写了反斜杠\n",
    "\n",
    "# 使用原生字符串\n",
    "s = '\\\\\\\\n123'\n",
    "pattern = r'\\\\\\\\n\\d{3}'\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4b23dcf",
   "metadata": {},
   "source": [
    "## 边界字符"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0fd3fab",
   "metadata": {},
   "source": [
    "![](images/10.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e49364b2",
   "metadata": {},
   "source": [
    "![](images/11.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "30a0e98d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:04:46.419610Z",
     "start_time": "2023-10-13T08:04:46.414355Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 11), match='hello world'>\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 匹配字符串开头 ^\n",
    "pattern = '^hello.*'\n",
    "str = 'hello world'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "16c1e838",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:06:30.050471Z",
     "start_time": "2023-10-13T08:06:30.046815Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 14), match='1234567@qq.com'>\n"
     ]
    }
   ],
   "source": [
    "# 匹配字符串结尾 $\n",
    "\n",
    "# 匹配一个{5,10}位的qq邮箱\n",
    "pattern = '[1-9]\\d{4,9}@qq.com$'\n",
    "\n",
    "qq = '1234567@qq.com.cn'\n",
    "print(re.match(pattern, qq))\n",
    "\n",
    "qq = '1234567@qq.com'\n",
    "print(re.match(pattern, qq))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eac6149a",
   "metadata": {},
   "source": [
    "![](images/12.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "180f1970",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:17:13.255397Z",
     "start_time": "2023-10-13T08:17:13.251924Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 7), match='abc qwe'>\n",
      "<re.Match object; span=(0, 10), match='123 heling'>\n"
     ]
    }
   ],
   "source": [
    "# \\b 匹配一个单词的边界\n",
    "pattern = r'.*\\bqwe'\n",
    "\n",
    "str = 'abc qwe'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "pattern = r'.*ing\\b'\n",
    "str = '123 heling a'\n",
    "\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e5d1183",
   "metadata": {},
   "source": [
    "![](images/13.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "5fb25d0f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:18:10.724553Z",
     "start_time": "2023-10-13T08:18:10.720053Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 8), match='abc aqwe'>\n",
      "<re.Match object; span=(0, 10), match='123 heling'>\n"
     ]
    }
   ],
   "source": [
    "# \\B 匹配非单词的边界\n",
    "pattern = r'.*\\Bqwe'\n",
    "str = 'abc aqwe'\n",
    "print(re.match(pattern, str))\n",
    "\n",
    "pattern = r'.*ing\\B'\n",
    "str = '123 helingand'\n",
    "print(re.match(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de23604a",
   "metadata": {},
   "source": [
    "## search函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cdb52ce5",
   "metadata": {},
   "source": [
    "search在一个字符串中搜索满足文本模式的字符串。\n",
    "\n",
    "语法格式如下：re.search(pattern, string, flags=0)\n",
    "\n",
    "![](images/14.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "bdb36f8d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:22:45.176374Z",
     "start_time": "2023-10-13T08:22:45.171348Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 3), match='abc'>\n",
      "abc\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 使用 search函数\n",
    "m = re.search('abc', 'abcdefg')\n",
    "\n",
    "print(m)\n",
    "print(m.group())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96700d0d",
   "metadata": {},
   "source": [
    "**match与search的区别：**\n",
    "\n",
    "re.match 只匹配字符串的开始，如果字符串开始不符合正则表达式，则匹配失败，函数返回 None；\n",
    "\n",
    "而 re.search 匹配整个字符串，直到找到一个匹配。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "95fa9533",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:25:40.864799Z",
     "start_time": "2023-10-13T08:25:40.858295Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "search方法的使用: <re.Match object; span=(12, 17), match='hello'>\n",
      "match方法的使用: None\n",
      "match: None\n",
      "search: <re.Match object; span=(2, 6), match='love'>\n"
     ]
    }
   ],
   "source": [
    "\"\"\" match方法与search方法的使用对比 \"\"\"\n",
    "import re\n",
    "\n",
    "pattern = 'hello'\n",
    "str = 'Hello world hello'\n",
    "\n",
    "result = re.search(pattern, str)\n",
    "print('search方法的使用:',result)\n",
    "\n",
    "r = re.match(pattern, str)\n",
    "print('match方法的使用:', r)\n",
    "\n",
    "\n",
    "pattern = 'love'\n",
    "str = 'I love you'\n",
    "print('match:', re.match(pattern, str))\n",
    "print('search:', re.search(pattern, str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9365e95",
   "metadata": {},
   "source": [
    "## 择一匹配  |  的使用\n",
    "\n",
    "search方法搜索一个字符串，要想搜索多个字符串，如搜索aa、bb和cc，最简单的方法是在文本模式字符串中使用择一匹配符号 '|'。择一匹配符号和逻辑或类似，只要满足任何一个，就算匹配成功"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "a377dc39",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:28:43.054201Z",
     "start_time": "2023-10-13T08:28:43.049748Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 2), match='aa'>\n",
      "<re.Match object; span=(0, 2), match='bb'>\n",
      "<re.Match object; span=(0, 2), match='cc'>\n",
      "<re.Match object; span=(9, 11), match='bb'>\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "pattern = 'aa|bb|cc'\n",
    "\n",
    "print(re.match(pattern,'aa'))\n",
    "print(re.match(pattern,'bb'))\n",
    "print(re.match(pattern,'cc'))\n",
    "print(re.search(pattern,'where is bb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "f505c9cb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:29:47.332659Z",
     "start_time": "2023-10-13T08:29:47.328681Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "<re.Match object; span=(0, 3), match='100'>\n"
     ]
    }
   ],
   "source": [
    "# 匹配0-100之间所有的数字\n",
    "pattern = r'[1-9]?\\d$|100$'\n",
    "\n",
    "s = '199'\n",
    "print(re.match(pattern, s))\n",
    "\n",
    "s = '100'\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "0d398eba",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:30:37.892905Z",
     "start_time": "2023-10-13T08:30:37.888383Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 1), match='y'>\n",
      "<re.Match object; span=(0, 1), match='y'>\n"
     ]
    }
   ],
   "source": [
    "# '[xyz]' 和 'x|y|z'\n",
    "pattern = '[xyz]'\n",
    "pattern1 = 'x|y|z'\n",
    "\n",
    "print(re.match(pattern, 'y'))\n",
    "print(re.match(pattern1, 'y'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "153baa63",
   "metadata": {},
   "source": [
    "## 分组\n",
    "\n",
    "![](images/15.png)\n",
    "\n",
    "如果一个模式字符串中有用一对圆括号括起来的部分，那么这部分就会作为一组，可以通过group方法的参数获取指定的组匹配的字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "05acc975",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:33:56.058098Z",
     "start_time": "2023-10-13T08:33:56.052512Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 11), match='010-1234567'>\n"
     ]
    }
   ],
   "source": [
    "\"\"\"不使用分组\"\"\"\n",
    "\n",
    "import re\n",
    "\n",
    "# 匹配座机号码  区号{3,4}-电话号码{5,8}\n",
    "pattern = r'\\d{3,4}-[1-9]\\d{4,7}$'\n",
    "s = '010-1234567'\n",
    "\n",
    "result = re.match(pattern, s)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "010d7829",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:37:33.888103Z",
     "start_time": "2023-10-13T08:37:33.882822Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 11), match='010-1234567'>\n",
      "010-1234567\n",
      "第一个分组： 010\n",
      "第二个分组： 1234567\n",
      "('010', '1234567')\n",
      "第一个分组： 010\n",
      "第二个分组： 1234567\n"
     ]
    }
   ],
   "source": [
    "\"\"\"使用分组\"\"\"\n",
    "\n",
    "pattern = r'(\\d{3,4})-([1-9]\\d{4,7}$)'\n",
    "s = '010-1234567'\n",
    "\n",
    "result = re.match(pattern, s)\n",
    "print(result)\n",
    "\n",
    "\"\"\"\n",
    "使用分组要了解如下几点：\n",
    "\n",
    "1. 用group方法获取指定组的值时，组从1开始，也就是说，group(1)获取第1组的值，group(2)获取第2组的值，以此类推。\n",
    "2. groups方法用于获取所有组的值，以元组形式返回。\n",
    "3. 所以除了使用group(1)获取第1组的值外，还可以使用groups()[0]获取第1组的值。获取第2组以及其它组的值的方式类似\n",
    "\"\"\"\n",
    "print(result.group())\n",
    "print('第一个分组：',result.group(1))\n",
    "print('第二个分组：',result.group(2))\n",
    "\n",
    "print(result.groups())\n",
    "print('第一个分组：',result.groups()[0])\n",
    "print('第二个分组：',result.groups()[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "d1d787ff",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:40:17.018613Z",
     "start_time": "2023-10-13T08:40:17.014561Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 31), match='<html><head>分组的使用</head></html>'>\n"
     ]
    }
   ],
   "source": [
    "\"\"\"\\num的使用\"\"\"\n",
    "\n",
    "s = '<html><head>分组的使用</head></html>'\n",
    "\n",
    "# 优化正则表达式 -- \\2 表示引用第2个分组  \\1表示引用第1个分组\n",
    "pattern =r'<(.+)><(.+)>.+</\\2></\\1>'\n",
    "\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "c7847c76",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:42:25.292039Z",
     "start_time": "2023-10-13T08:42:25.288821Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 31), match='<html><head>分组的使用</head></html>'>\n"
     ]
    }
   ],
   "source": [
    "\"\"\"(?P<别名>)\"\"\"\n",
    "\n",
    "#  起名 ?P<要起的别名> -- 引用  (?P=别名)\n",
    "\n",
    "s = '<html><head>分组的使用</head></html>'\n",
    "pattern = r'<(?P<k1>.+)><(?P<k2>.+)>.+</(?P=k2)></(?P=k1)>'\n",
    "\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "494cd07c",
   "metadata": {},
   "source": [
    "## re模块中其他常用的函数\n",
    "### sub和subn搜索与替换\n",
    "\n",
    "sub函数和subn函数用于实现搜索和替换功能。这两个函数的功能几乎完全相同，都是将某个字符串中所有匹配正则表达式的部分替换成其他字符串。\n",
    "\n",
    "用来替换的部分可能是一个字符串，也可以是一个函数，该函数返回一个用来替换的字符串。\n",
    "\n",
    "sub函数返回替换后的结果，\n",
    "\n",
    "subn函数返回一个元组，元组的第1个元素是替换后的结果，第2个元素是替换的总数。\n",
    "\n",
    "语法格式如下：re.sub(pattern, repl, string, count=0, flags=0)\n",
    "\n",
    "![](images/16.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "24ae0db3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:48:40.318418Z",
     "start_time": "2023-10-13T08:48:40.312772Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2004-959-559 \n",
      "2004959559\n",
      "('2004959559', 15)\n",
      "替换的结果： 2004959559\n",
      "替换的次数： 15\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "# sub和subn\n",
    "phone = \"2004-959-559 # 这是一个国外电话号码\"\n",
    "\n",
    "# 替换目标字符串中注释\n",
    "pattern = r'#.*'\n",
    "result = re.sub(pattern, '', phone)\n",
    "print(result)\n",
    "\n",
    "# 删除非数字的字符串 \\D\n",
    "pattern = r'\\D'\n",
    "result = re.sub(pattern, '', phone)\n",
    "print(result)\n",
    "\n",
    "# 调用subn\n",
    "result = re.subn(pattern, '', phone)\n",
    "print(result)\n",
    "print('替换的结果：',result[0])\n",
    "print('替换的次数：',result[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "360916ba",
   "metadata": {},
   "source": [
    "### compile 函数\n",
    "compile 函数用于编译正则表达式，生成一个正则表达式（Pattern）对象，\n",
    "\n",
    "供 match() 和 search() 这两个函数使用。\n",
    "\n",
    "语法格式为：\n",
    "\n",
    "![](images/17.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "1e75606b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:50:39.842251Z",
     "start_time": "2023-10-13T08:50:39.838429Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<re.Match object; span=(0, 4), match='one1'>\n",
      "<re.Match object; span=(0, 4), match='one1'>\n"
     ]
    }
   ],
   "source": [
    "# compile\n",
    "s = 'one1 two2 3 4_'\n",
    "\n",
    "# 生成正则表达式\n",
    "pattern = r'\\w+'\n",
    "regex = re.compile(pattern)\n",
    "\n",
    "print(regex.match(s))\n",
    "print(re.match(pattern, s))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9697b570",
   "metadata": {},
   "source": [
    "### findall 函数\n",
    "在字符串中找到正则表达式所匹配的所有子串，并返回一个列表，如果没有找到匹配的，则返回空列表。\n",
    "\n",
    "语法格式如下：\n",
    "\n",
    "![](images/18.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "861e936a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:55:57.156900Z",
     "start_time": "2023-10-13T08:55:57.151155Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['ab', 'c', 'd', '1', '2', '_', 'helloword', 'ac']\n",
      "<re.Match object; span=(0, 2), match='ab'>\n",
      "<re.Match object; span=(0, 2), match='ab'>\n"
     ]
    }
   ],
   "source": [
    "# findall()\n",
    "pattern = r'\\w+'\n",
    "s = 'ab c d 1 2 _ helloword # ac @'\n",
    "\n",
    "result = re.findall(pattern, s)\n",
    "print(result)\n",
    "\n",
    "# match 和 search 是匹配一次，findall 匹配所有\n",
    "print(re.match(pattern, s))\n",
    "print(re.search(pattern, s))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "710341a5",
   "metadata": {},
   "source": [
    "### finditer函数\n",
    "和 findall 类似，在字符串中找到正则表达式所匹配的所有子串，并把它们作为一个迭代器返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "42d8f419",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:58:20.084852Z",
     "start_time": "2023-10-13T08:58:20.081189Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<callable_iterator object at 0x10400e220>\n",
      "ab c d 1 2 _ helloword ac "
     ]
    }
   ],
   "source": [
    "# finditer()，返回的是 迭代器对象--内含许多 match对象\n",
    "result = re.finditer(pattern, s) \n",
    "print(result)\n",
    "\n",
    "for i in result:\n",
    "    print(i.group(), end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a820617",
   "metadata": {},
   "source": [
    "### split函数\n",
    "split函数用于根据正则表达式分隔字符串，也就是说，将字符串与模式匹配的子字符串都作为分隔符来分隔这个字符串\n",
    "\n",
    "split函数返回一个列表形式的分隔结果，每一个列表元素都是分隔的子字符串。\n",
    "\n",
    "语法格式如下：\n",
    "\n",
    "![](images/19.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "0a55a7ca",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T08:59:55.738634Z",
     "start_time": "2023-10-13T08:59:55.734932Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['a ', ' b ', ' c ', ' d']\n",
      "['a ', ' b ', ' c 3 d']\n"
     ]
    }
   ],
   "source": [
    "# split()\n",
    "s = 'a 1 b 2 c 3 d'\n",
    "pattern = r'\\d+'\n",
    "result = re.split(pattern, s)\n",
    "\n",
    "print(result)\n",
    "\n",
    "# 指定分隔的次数\n",
    "print(re.split(pattern, s, maxsplit=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb79b97b",
   "metadata": {},
   "source": [
    "## 贪婪模式和非贪婪模式"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "939f7d7a",
   "metadata": {},
   "source": [
    "贪婪模式指Python里数量词默认是贪婪的，总是尝试匹配尽可能多的字符。\n",
    "\n",
    "非贪婪模式与贪婪相反，总是尝试匹配尽可能少的字符\n",
    "\n",
    "可以使用\"*\"，\"?\"，\"+\"，\"{m,n}\"后面加上？，使贪婪变成非贪婪。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "52545063",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T09:05:00.425738Z",
     "start_time": "2023-10-13T09:05:00.420141Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "123\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "# 默认为贪婪模式\n",
    "s = 'abc123'\n",
    "pattern = r'abc(\\d+)'\n",
    "result = re.match(pattern, s)\n",
    "print(result.group(1))\n",
    "\n",
    "# 修改为非贪婪模式\n",
    "pattern = r'abc(\\d+?)'\n",
    "result = re.match(pattern, s)\n",
    "print(result.group(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ecf5154",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6f0f8c38",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "248.1875px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
